#include "commandlinestream.h"
#include "lib/stringex.h"
#include "log/logger.h"
#include "lib/misc.h"
#include "commandlinemgrbase.h"

//linux fn
#define FN_KEY_MAX_LEN 3
#define FN_KEY_CODE_START1 0x1b
#define FN_KEY_CODE_START2 0x5b

#define FN_KEY_UP  0x41
#define FN_KEY_DOWN 0x42
#define FN_KEY_LEFT 0x44
#define FN_KEY_RIGHT 0x43
#define FN_KEY_DELETE 0x337e

CommandLineStream::CommandLineStream()
{
}

CommandLineStream::~CommandLineStream()
{
}

void CommandLineStream::AttacthCommandMgr(CommandLineMgrBase *mgr)
{
    m_commandMgr = mgr;
}

void CommandLineStream::DettachCommandMgr()
{
    m_commandMgr = nullptr;
}

void CommandLineStream::Start()
{
    if(m_thread.IsRunning())
        return;
    
    m_thread.SetThreadName("cli");
    m_thread.Start([=](){HandleLoop();});
}

void CommandLineStream::Stop()
{
    m_thread.Stop();
}

void CommandLineStream::AddRecvByte(uint8_t c)
{
    if(!m_thread.IsRunning())
        return;
        
    m_recvQ.Post((char)c, 0);
}

void CommandLineStream::SendTo(const char *data)
{
    OnWriteStream(data);
}

void CommandLineStream::SendResp(const char *data)
{
    OnWriteStream(NEWLINE);

    if(data != nullptr)
    {
        OnWriteStream(NEWLINE);
        OnWriteStream("  ");
        OnWriteStream(data);
        OnWriteStream(NEWLINE);
    }

    OnWriteStream(NEWLINE"#");
}

bool CommandLineStream::Parse(const std::string &line, CommandParamItem &item)
{
    if(line.empty())
        return false;
        
    std::vector<std::string> tokens = StringEx::Split(line, " ", true, true);
    if(tokens.size() == 0)
        return false;

    item.Name = tokens[0];
    tokens.erase(tokens.begin());
    item.Params = std::move(tokens);

    return true;
}

void CommandLineStream::HandleLine(const std::string &line)
{
    if(line.size() == 0)
        return;

    CommandParamItem item;
    bool ok = Parse(m_line, item);
    if(!ok)
    {
        OnWriteStream(NEWLINE"#");
        return;
    }
    
    AddCmdToQueue(line);
    
    item.Stream = this;
    if(m_commandMgr != nullptr)
    {
        m_commandMgr->ProcessCommand(item);
    }
    
    if(!item.CancelSendTo)
    {
        //resp
        if(!item.AckOnlyResp)
        {
            SendResp(item.Resp.c_str());
        }
        else
        {
            OnWriteStream(item.Resp.c_str());
        }
    }
}

void CommandLineStream::HandleLoop()
{
    char preC = 0;
    while(true)
    {
        char c;
        bool ok = m_recvQ.Wait(c);
        
        if(!ok)
            continue;

        HandleRecvByteParse(preC, c);
        preC = c;
    }
}

void CommandLineStream::HandleRecvByteParse(char preC, char c)
{
#define BACK_SHOW(c)  do{\
    std::string str;\
    str.push_back(c);\
    OnWriteStream(str.c_str());\
}while(0)

    bool isAsciiStr = (int)c >= 32 && (int)c <=126;
    bool isNewLine = c == '\r' || c == '\n';
    bool isBackOrDelete = (int)c == 0x7F || (int)c == 0x08;  //delete or backspace or page

    //功能码 
    if((int)preC == FN_KEY_CODE_START1 && (int)c == FN_KEY_CODE_START2)
    {
        m_fnKeyCode = 0;
        m_fnRecvCount = 0;
        m_fnRecvStart = true;
        return;
    }
    //功能码
    if(m_fnRecvStart) //recv 1-3
    {
        m_fnKeyCode |= ((uint8_t)(c)) << (8*m_fnRecvCount);
        m_fnRecvCount++;
        //匹配,成功就复位
        bool isMatch = true;
        bool isSendBack = false;
        int oldLineLen = m_line.size();
        if(m_fnKeyCode == FN_KEY_UP)
        {
            m_line = m_historyCmds[m_currentExecCmdIndex];
            m_currentExecCmdIndex--;
            if(m_currentExecCmdIndex < 0)
            {
                m_currentExecCmdIndex = 0;
            }
            isSendBack = true;
        }
        else if(m_fnKeyCode == FN_KEY_DOWN)
        {
            m_line = m_historyCmds[m_currentExecCmdIndex];
            m_currentExecCmdIndex++;
            if(m_currentExecCmdIndex >= m_historyCmds.size())
            {
                m_currentExecCmdIndex = m_historyCmds.size() - 1;
            }
            isSendBack = true;
        }
        else if(m_fnKeyCode == FN_KEY_LEFT)
        {

        }
        else if(m_fnKeyCode == FN_KEY_RIGHT)
        {

        }
        else if(m_fnKeyCode == FN_KEY_DELETE)
        {

        }
        else
        {
            isMatch = false;
        }

        if(isSendBack)
        {    
            //删除
            if(oldLineLen > 0)
            {
                for(int i = 0; i < oldLineLen; i++)
                {
                    OnWriteStream("\b \b");
                }
            }
            
            OnWriteStream(m_line.c_str());
        }

        if(isMatch || m_fnRecvCount >= FN_KEY_MAX_LEN)
        {
            m_fnRecvStart = 0;
        }

        return;
    }

    //特殊字符处理
    if(c == 0x0c)
    {
        OnWriteStream("\033[2J\033[H#");
        return;
    }

    //backspace
    if(isBackOrDelete)
    {
        if(m_line.size() > 0)
        {
            m_line.pop_back();
            OnWriteStream("\b \b");
        }

        return;                
    }

    //特殊字符
    if(!isAsciiStr && !isNewLine)
    {
        return;
    }

    //回显 
    BACK_SHOW(c);

    //处理
    if(isAsciiStr)
        m_line.push_back(c);
    
    if(m_line.size() > COMMANDLINE_LINE_MAX)
    {
        LogDebug()<<"oops"<<"m_line.size() > COMMANDLINE_LINE_MAX";//oops
        m_line.clear();
    }

    if(isNewLine)
    {
        if(m_line.size() > 0)
        {
            HandleLine(m_line);
        }
        else
        {
            OnWriteStream(NEWLINE"#");
        }
        m_line.clear();
    }
}

void CommandLineStream::AddCmdToQueue(const std::string &cmd)
{
    if(m_historyCmds.size() > 0 && cmd == m_historyCmds[m_historyCmds.size() - 1])
    {
        return;
    }

    if(m_historyCmds.size() >= COMMANDLINE_HISTORY_MAX)
    {
        m_historyCmds.erase(m_historyCmds.begin());
    }

    m_historyCmds.push_back(cmd);
    m_currentExecCmdIndex = m_historyCmds.size() - 1;
}
